use anyhow::Error;

use anyhow::Ok;
// use async_openai::config::Config;
// use async_openai::config::OpenAIConfig;
use async_openai::{
    types::{
        ChatCompletionRequestAssistantMessageArgs, ChatCompletionRequestSystemMessageArgs,
        ChatCompletionRequestUserMessageArgs, CreateChatCompletionRequestArgs,
    },
    // Client,
};

pub const TEST_CONTENT: &str = r#"
Here is the equivalent Rust code for the C double-ended queue implementation, using the C code you provided as a reference. I will use Rust's `VecDeque` as the underlying container to store the elements, but to stay faithful to the C code, I will implement the queue from scratch using `Box` for heap allocation.

### Rust Code:


// Copyright (c) 2005-2008, Simon Howard

Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

```rust

use std::ptr;
use std::option::Option::None;

type QueueValue = Option<Box<dyn std::any::Any>>;

/// A double-ended queue.
pub struct Queue {
    head: Option<Box<QueueEntry>>,
    tail: Option<Box<QueueEntry>>,
}

/// A value stored in a Queue.
pub struct QueueEntry {
    data: QueueValue,
    prev: Option<Box<QueueEntry>>,
    next: Option<Box<QueueEntry>>,
}

impl Queue {
    /// Creates a new double-ended queue.
    pub fn new() -> Option<Self> {
        Some(Queue {
            head: None,
            tail: None,
        })
    }

    /// Destroys a queue.
    pub fn free(self) {
        // The queue will be dropped automatically when it goes out of scope
    }

    /// Adds a value to the head of a queue.
    pub fn push_head(&mut self, data: QueueValue) -> bool {
        let new_entry = Box::new(QueueEntry {
            data,
            prev: None,
            next: self.head.take(),
        });

        if let Some(ref mut head) = self.head {
            head.prev = Some(new_entry);
        } else {
            self.tail = Some(new_entry.clone());
        }

        self.head = Some(new_entry);
        true
    }

    /// Removes a value from the head of a queue.
    pub fn pop_head(&mut self) -> QueueValue {
        if self.is_empty() {
            None
        } else {
            let head = self.head.take().unwrap();
            self.head = head.next.take();

            if self.head.is_none() {
                self.tail = None;
            } else {
                if let Some(ref mut head) = self.head {
                    head.prev = None;
                }
            }

            head.data
        }
    }

    /// Reads a value from the head of a queue, without removing it.
    pub fn peek_head(&self) -> QueueValue {
        self.head.as_ref().map(|entry| entry.data.clone()).unwrap_or(None)
    }

    /// Adds a value to the tail of a queue.
    pub fn push_tail(&mut self, data: QueueValue) -> bool {
        let new_entry = Box::new(QueueEntry {
            data,
            prev: self.tail.take(),
            next: None,
        });

        if let Some(ref mut tail) = self.tail {
            tail.next = Some(new_entry.clone());
        } else {
            self.head = Some(new_entry.clone());
        }

        self.tail = Some(new_entry);
        true
    }

    /// Removes a value from the tail of a queue.
    pub fn pop_tail(&mut self) -> QueueValue {
        if self.is_empty() {
            None
        } else {
            let tail = self.tail.take().unwrap();
            self.tail = tail.prev.take();

            if self.tail.is_none() {
                self.head = None;
            } else {
                if let Some(ref mut tail) = self.tail {
                    tail.next = None;
                }
            }

            tail.data
        }
    }

    /// Reads a value from the tail of a queue, without removing it.
    pub fn peek_tail(&self) -> QueueValue {
        self.tail.as_ref().map(|entry| entry.data.clone()).unwrap_or(None)
    }

    /// Queries if any values are currently in a queue.
    pub fn is_empty(&self) -> bool {
        self.head.is_none()
    }
}

fn main() {
    // Test the queue implementation in Rust

    let mut queue = Queue::new().unwrap();
    queue.push_head(Some(Box::new(42)));
    queue.push_tail(Some(Box::new(24)));

    println!("Pop head: {:?}", queue.pop_head());
    println!("Peek tail: {:?}", queue.peek_tail());
    println!("Pop tail: {:?}", queue.pop_tail());
}
```

### Explanation of the Rust code:

1. **Queue Structure**: 
   - The `Queue` struct holds `Option<Box<QueueEntry>>` for both `head` and `tail`, which means each element in the queue (a `QueueEntry`) is heap-allocated.
   
2. **QueueEntry Structure**:
   - The `QueueEntry` struct stores the data (`QueueValue`), along with pointers to the previous and next elements in the queue.
   
3. **Methods**:
   - Methods like `push_head`, `push_tail`, `pop_head`, `pop_tail`, `peek_head`, and `peek_tail` implement the corresponding functionalities of the C code.
   - The `is_empty` method checks if the queue is empty by verifying if `head` is `None`.
   
4. **Memory Management**:
   - Rust’s ownership and memory management model automatically handles memory deallocation (similar to `free` in C). So, there is no need for manual memory management (i.e., `malloc` and `free` in C).

5. **QueueValue**:
   - The `QueueValue` is a boxed `dyn Any` trait object, which allows us to store any type of value in the queue. You can store a value of any type that implements the `Any` trait.

This implementation is safe and idiomatic in Rust, leveraging Rust's memory safety features to ensure that memory management is handled automatically without needing to manually allocate or free memory as in C.// 
"#;

pub async fn chat_invoke(prompt: &String) -> Result<String, Error> {
    println!("start chatgpt chat_invoke");
    // return Ok(TEST_CONTENT.to_string());
    // let url = "https://free.v36.cm";
    // let config = OpenAIConfig::new()
    //     .with_api_base(url)
    //     .with_api_key(std::env::var("OPENAI_API_KEY").unwrap());
    // let client = Client::with_config(config);

    // println!("std::env:: {:?}", std::env::var("OPENAI_API_KEY"));

    let request = CreateChatCompletionRequestArgs::default()
        .max_tokens(16384u32)
        // .model("gpt-3.5-turbo")
        .model("chatgpt-4o-latest")
        .messages([
            ChatCompletionRequestSystemMessageArgs::default()
                .content("You are a C and Rust developer.")
                .build()?
                .into(),
            ChatCompletionRequestUserMessageArgs::default()
                .content("You can search any ")
                .build()?
                .into(),
            ChatCompletionRequestAssistantMessageArgs::default()
                .content("You can use `cargo check` order check the result")
                .build()?
                .into(),
            ChatCompletionRequestUserMessageArgs::default()
                .content(prompt.as_str())
                .build()?
                .into(),
        ])
        .build()?;

    // println!("request-max_tokens: {:?}", request.max_tokens);
    // println!("{}", serde_json::to_string(&request).unwrap());
    use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};

    let mut headers = HeaderMap::new();
    // headers.insert(AUTHORIZATION, HeaderValue::from_str("Bearer sk-4dccUz3MAkKxP71JF07f7471FdA34aEb92AdDcE5596c0aEe").unwrap()); ，免费
    headers.insert(AUTHORIZATION, HeaderValue::from_str("Bearer sk-pADJBsJmhkhzWLhqA772Bc22D2Dd4895Ac20FcDf7620Ab76").unwrap());
    // c2rust sk-pADJBsJmhkhzWLhqA772Bc22D2Dd4895Ac20FcDf7620Ab76
    let fetch_result = reqwest::Client::new()
        // .post("https://free.v36.cm/v1/chat/completions")
        .post("https://api.vveai.com/v1/chat/completions")
        .headers(headers)
        .json(&request)
        .send()
        .await?;
    let response: serde_json::Value = fetch_result.json().await?;
    // println!("CHAT_GPT response: {:?}", response);

    // let response = client.chat().create(request).await?;
    let mut result = String::new();
    if let Some(choices_unwrap) = response.get("choices") {
        if let Some(choices_unwrap) = choices_unwrap.as_array() {
            for choice in choices_unwrap {
                if let Some(message) = choice.get("message") {
                    if let Some(content) = message.get("content") {
                        println!("{:?}", content);
                        result.push_str(content.as_str().unwrap());
                    }
                }
            }
        }
    }
    // println!("end chatgpt chat_invoke: {:?}", result);
    Ok(result)

}